import { md5 as MD5 } from 'js-md5';
import { v4 as uuidv4 } from 'uuid';
import { parseAjaxResponse, postByFormData } from '~/common/request';
import qs, { UrlObject, ParsedQuery } from 'query-string';
import { useUserStore } from '~/store/modules/user.ts';
import { APP_URL_TOKEN_PARAM, isDev } from '~/common/index.ts';

const baseUrl = import.meta.env.VITE_APP_BASE_URL;

/**
 * 拼接路径
 * @param currentPath
 * @param parentPath
 */
export const combinePath = (currentPath: string, parentPath?: string) => {
  if (!parentPath) {
    return currentPath;
  } else {
    if (parentPath.endsWith('/')) {
      parentPath = parentPath.substring(0, parentPath.length - 1);
    }
    if (currentPath.startsWith('/')) {
      currentPath = currentPath.substring(1, currentPath.length);
    }
    return `${parentPath}/${currentPath}`;
  }
};

export function registerResizeXHandler(
  e: MouseEvent,
  handler: (e: MouseEvent, moveX: number) => void
) {
  const isDrag = true;
  let clientX = e.clientX;
  const pointerId = 1;
  const target = e.currentTarget as HTMLElement;

  document.onmousemove = (e: MouseEvent) => {
    if (isDrag) {
      const moveX = e.clientX - clientX;
      clientX = e.clientX;
      handler(e, moveX);
    }
  };

  document.onmouseup = () => {
    document.onmousemove = null;
    document.onmouseup = null;
    target.releasePointerCapture(pointerId);
  };
  target.setPointerCapture(pointerId);
}

export const getUuid = (): string => {
  return uuidv4();
};

export const digestByMD5 = (message: string) => {
  return MD5.hex(message);
};

export const getChecksum = (fileChunk: Blob): Promise<string> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsArrayBuffer(fileChunk);
    reader.onload = e => {
      let result = e.target?.result;
      if (!result) {
        throw new Error('读取文件失败');
      }
      const md5sum = MD5.hex(result);
      resolve(md5sum);
    };
    reader.onerror = error => reject(error);
  });
};

/**
 * 分片大小的8M
 */
const chunkSize = 1024 * 1024 * 8;

export interface FileUploadOption {
  projectId: string;

  file: File;
}

/**
 *
 * @param options 上传配置
 * @param uploadFileChunkSuccess 分片上传成功回调
 * @param mergeFileChunkSuccess  合并分片成功回调
 */
export const doFileUpload = async (
  options: FileUploadOption,
  uploadFileChunkSuccess?: (percentage: number) => void,
  mergeFileChunkSuccess?: () => void
) => {
  const fileSize = options.file.size;
  let fileName = options.file.name;
  const chunkTotal = Math.ceil(fileSize / chunkSize);
  const requestId = getUuid();
  if (chunkTotal > 0) {
    for (
      let chunkNumber = 0, start = 0;
      chunkNumber < chunkTotal;
      chunkNumber++, start += chunkSize
    ) {
      let end = Math.min(fileSize, start + chunkSize);
      const fileChunk = options.file.slice(start, end);

      // const checksum = await getChecksum(fileChunk);

      const result = await postByFormData<void>('/upload/chunk', {
        fileChunk,
        chunkNumber,
        requestId
      });
      parseAjaxResponse({
        data: result,
        showErrorMessage: false
      });

      let percentage = (end * 100) / fileSize;
      percentage = parseFloat(percentage.toFixed(2));
      if (uploadFileChunkSuccess) {
        try {
          uploadFileChunkSuccess(percentage);
        } catch (e) {
          if (e instanceof Error && e.message === 'fileNotFound') {
            // 终止上传
            return;
          } else {
            throw e;
          }
        }
      }
    }

    let projectId = options.projectId;
    await postByFormData<void>('/upload/merge', {
      requestId,
      chunkTotal,
      fileName,
      projectId
    });

    if (mergeFileChunkSuccess) {
      mergeFileChunkSuccess();
    }
  }
};

/**
 * 文本转blob
 * @param text
 */
export const textToBlob = (text: string) => {
  let buffer = new TextEncoder().encode(text);
  return new Blob([buffer], { type: 'text/plain' });
};

/**
 * 文件下载
 * @param content
 * @param fileName
 */
export const downloadFile = (content: Blob, fileName: string) => {
  let a = document.createElement('a');
  a.download = fileName;
  a.style.display = 'none';
  let url = URL.createObjectURL(content);
  a.href = url;
  document.body.appendChild(a);
  a.click();
  URL.revokeObjectURL(url);
  document.body.removeChild(a);
};

export const getUrl = (url: string) => {
  let urlData = qs.parseUrl(url);
  let _url = urlData.url;
  if (!isDev) {
    _url = 'http://' + window.location.host + baseUrl + _url;
  } else {
    _url = baseUrl + _url;
  }
  let queryObj: ParsedQuery = { ...urlData.query };
  queryObj[APP_URL_TOKEN_PARAM] = useUserStore().getToken() || '';

  let urlObj: UrlObject = {
    url: _url,
    query: queryObj
  };
  return qs.stringifyUrl(urlObj);
};
